package com.dynabook.ems.utils;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.dynabook.ems.common.ErrorCode;
import com.dynabook.ems.exception.BusinessException;
import com.dynabook.ems.model.entity.EmsMainEngine;
import com.dynabook.ems.model.enums.ModelStatusEnum;
import com.dynabook.ems.service.EmsMainEngineService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.LocalDateTime;

/**
 * 样品状态管理工具类
 * 用于处理样品数量变更和状态计算
 *
 * @author system
 * @date 2025-01-28
 */
@Slf4j
@Component
public class SampleStatusUtils {

    @Resource
    @Lazy
    private EmsMainEngineService emsMainEngineService;

    /**
     * 更新样品数量并根据数量变化更新状态（不包含工单号）
     * @param borrowNum 借用数量
     * @param fixedNo 设备编号
     * @param type 操作类型 1:归还(库存+,使用-) 2:借出(库存-,使用+) 3:报废恢复(库存+,报废-) 4:报废(库存-,报废+)
     * @param isNeed 是否需要清空用户信息 1:清空用户信息 2:清空所有相关信息 3:不清空
     * @return 更新成功返回true
     * @throws BusinessException 当业务逻辑错误或数据更新失败时抛出，触发事务回滚
     */
    public Boolean updateSampleQuantityAndStatus(Integer borrowNum, String fixedNo, Integer type, Integer isNeed) {
        return updateSampleQuantityAndStatus(borrowNum, fixedNo, type, isNeed, null);
    }

    /**
     * 更新样品数量并根据数量变化更新状态（包含工单号）
     * @param borrowNum 借用数量
     * @param fixedNo 设备编号
     * @param type 操作类型 1:归还(库存+,使用-) 2:借出(库存-,使用+) 3:报废恢复(库存+,报废-) 4:报废(库存-,报废+)
     * @param isNeed 是否需要清空用户信息 1:清空用户信息 2:清空所有相关信息 3:不清空
     * @param workOrderNum 工单号（可选，传null表示不设置工单号）
     * @return 更新成功返回true
     * @throws BusinessException 当业务逻辑错误或数据更新失败时抛出，触发事务回滚
     */
    @Transactional(rollbackFor = Exception.class)
    public Boolean updateSampleQuantityAndStatus(Integer borrowNum, String fixedNo, Integer type,Integer isNeed,String workOrderNum) {
        try {

            // 参数校验
            if (borrowNum == null || borrowNum <= 0) {
                log.error("借用数量不能为空或小于等于0: {}", borrowNum);
                return false;
            }
            if (StrUtil.isBlank(fixedNo)) {
                log.error("设备编号不能为空");
                return false;
            }
            if (type == null || (type < 1 || type > 4)) {
                log.error("操作类型错误，必须为1-4之间: {}", type);
                return false;
            }

            // 查询当前设备信息
            EmsMainEngine mainEngine = emsMainEngineService.getOne(
                new LambdaQueryWrapper<EmsMainEngine>()
                    .eq(EmsMainEngine::getFixedNo, fixedNo)
            );
            
            if (mainEngine == null) {
                log.error("未找到设备信息，fixedNo: {}", fixedNo);
                throw new BusinessException(ErrorCode.PARAMS_ERROR, "未找到设备信息，fixedNo: " + fixedNo);
            }

            // 获取当前数量
            Integer totalNum = mainEngine.getTotalNum() != null ? mainEngine.getTotalNum() : 0;
            Integer inventoryNum = mainEngine.getInventoryNum() != null ? mainEngine.getInventoryNum() : 0;
            Integer usedNum = mainEngine.getUsedNum() != null ? mainEngine.getUsedNum() : 0;
            Integer scrapNum = mainEngine.getScrapNum() != null ? mainEngine.getScrapNum() : 0;
            if(isNeed != 3){
                // 根据类型更新数量
                switch (type) {
                    case 1: // 归还：库存+，使用-
                        inventoryNum += borrowNum;
                        usedNum -= borrowNum;
                        break;
                    case 2: // 借出：库存-，使用+
                        inventoryNum -= borrowNum;
                        usedNum += borrowNum;
                        break;
                    case 3: // 报废恢复：库存+，报废-
                        inventoryNum += borrowNum;
                        scrapNum -= borrowNum;
                        break;
                    case 4: // 报废：库存-，报废+
                        inventoryNum -= borrowNum;
                        scrapNum += borrowNum;
                        break;
                    // 本人已借恢复：库存-，报废+
                    case 5:
                        inventoryNum -= borrowNum;
                        scrapNum += borrowNum;
                        break;
                    default:
                        log.error("不支持的操作类型: {}", type);
                        throw new BusinessException(ErrorCode.PARAMS_ERROR, "不支持的操作类型: " + type);
                }
            }
            // 数量校验，确保不出现负数
            if (inventoryNum < 0 || usedNum < 0 || scrapNum < 0) {
                log.error("数量更新后出现负数，操作失败。库存:{}, 使用:{}, 报废:{}", inventoryNum, usedNum, scrapNum);
                throw new BusinessException(ErrorCode.SYSTEM_ERROR, 
                    String.format("数量更新后出现负数，操作失败。库存:%d, 使用:%d, 报废:%d", inventoryNum, usedNum, scrapNum));
            }

            // 根据更新后的数量确定状态
            ModelStatusEnum newStatus;
            if (usedNum > 0 && usedNum < totalNum) {
                // 部分使用中
                newStatus = ModelStatusEnum.PART_USING;
            } else if (usedNum > 0 && usedNum.equals(totalNum)) {
                // 全部使用中
                newStatus = ModelStatusEnum.USING;
            } else if (usedNum == 0 && scrapNum == 0) {
                // 在库
                newStatus = ModelStatusEnum.IN_STORE;
            } else if (usedNum == 0 && scrapNum > 0 && scrapNum.equals(totalNum)) {
                // 全部已报废
                newStatus = ModelStatusEnum.SCRAPED;
            } else if (usedNum == 0 && scrapNum > 0 && scrapNum < totalNum) {
                // 部分已报废
                newStatus = ModelStatusEnum.PART_SCRAPED;
            } else {
                log.warn("无法确定状态，使用默认状态IN_STORE。totalNum:{}, usedNum:{}, scrapNum:{}", totalNum, usedNum, scrapNum);
                newStatus = ModelStatusEnum.IN_STORE;
            }

            // 更新设备信息
//            if(isWorkerOrder==1){
//                mainEngine.setCanWorkOrder(1);
//            }
            mainEngine.setInventoryNum(inventoryNum);
            mainEngine.setUsedNum(usedNum);
            mainEngine.setScrapNum(scrapNum);
            mainEngine.setModelStatus(newStatus.getValue());
            mainEngine.setUpdateTime(LocalDateTime.now());
            if(StrUtil.isNotBlank(workOrderNum)){
                mainEngine.setWorkOrderNumber(workOrderNum);
//                mainEngine.setCanWorkOrder(1);
            }
            switch(isNeed) {
                case 1:
                    mainEngine.setUserId(null);
                    mainEngine.setUserName(null);
                    mainEngine.setPredictDate(null);
                    break;
                case 2:
                case 3:
                    mainEngine.setUserId(null);
                    mainEngine.setUserName(null);
                    mainEngine.setPredictDate(null);
                    mainEngine.setApproverId(null);
                    mainEngine.setStartDate(null);
                    mainEngine.setApproveDate(null);
                    mainEngine.setApproverName(null);
                    break;
                default:
                    break;
            }
            
            boolean updateResult = emsMainEngineService.updateById(mainEngine);
            
            if (updateResult) {
                log.info("样品数量和状态更新成功。fixedNo:{}, 操作类型:{}, 数量:{}, 新状态:{}", 
                    fixedNo, type, borrowNum, newStatus.getText());
                log.info("更新后数量 - 总数:{}, 库存:{}, 使用:{}, 报废:{}", 
                    totalNum, inventoryNum, usedNum, scrapNum);
                return true;
            } else {
                log.error("样品数量和状态更新失败。fixedNo:{}", fixedNo);
                throw new BusinessException(ErrorCode.SYSTEM_ERROR, "数据库更新失败，fixedNo: " + fixedNo);
            }
            
        } catch (BusinessException e) {
            // 业务异常直接抛出，触发事务回滚
            log.error("业务异常：{}", e.getMessage());
            throw e;
        } catch (Exception e) {
            log.error("更新样品数量和状态时发生异常，fixedNo:{}, type:{}, borrowNum:{}", fixedNo, type, borrowNum, e);
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "更新样品数量和状态时发生系统异常");
        }
    }



    /**
     * 操作类型枚举
     */
    public enum OperationType {
        RETURN(1, "归还"),
        BORROW(2, "借出"),
        SCRAP_RESTORE(3, "报废恢复"),
        SCRAP(4, "报废"),
        SELF_SCRAP(5, "本人已借恢复");

        private final int code;
        private final String desc;

        OperationType(int code, String desc) {
            this.code = code;
            this.desc = desc;
        }

        public int getCode() {
            return code;
        }

        public String getDesc() {
            return desc;
        }

        public static OperationType getByCode(int code) {
            for (OperationType type : values()) {
                if (type.getCode() == code) {
                    return type;
                }
            }
            throw new IllegalArgumentException("未知的操作类型: " + code);
        }
    }
}